from flask import Flask, request, jsonify, render_template_string
import json
import threading
import time
from tcp_client import TCPClient

app = Flask(__name__)

# 全局TCP客户端实例
tcp_client = None
client_lock = threading.Lock()
tcp_server_available = False

def get_tcp_client():
    """获取TCP客户端实例（线程安全）"""
    global tcp_client, tcp_server_available
    with client_lock:
        if tcp_client is None or not tcp_client.connected:
            print("🔄 创建新的TCP客户端连接...")
            tcp_client = TCPClient('localhost', 8080)
            if tcp_client.connect():
                tcp_server_available = True
                print("✅ TCP服务器可用")
                return tcp_client
            else:
                tcp_server_available = False
                print("❌ TCP服务器不可用")
                return None
        return tcp_client

def create_mock_suggestions(keyword):
    """创建模拟建议数据"""
    if not keyword:
        return []
    
    base_suggestions = [
        f"{keyword} 教程",
        f"{keyword} 文档", 
        f"{keyword} 使用方法",
        f"{keyword} 最佳实践",
        f"{keyword} 示例代码"
    ]
    
    # 根据关键词长度调整建议数量
    if len(keyword) > 3:
        base_suggestions.extend([
            f"{keyword} 高级技巧",
            f"{keyword} 常见问题"
        ])
    
    return base_suggestions[:5]  # 最多返回5个建议

def create_mock_results(keyword):
    """创建模拟搜索结果"""
    if not keyword:
        return []
    
    return [
        {
            "id": 1,
            "title": f"关于 {keyword} 的完整指南",
            "link": f"https://example.com/{keyword}-guide",
            "abstract": f"这是一篇关于 {keyword} 的详细指南，涵盖了基本概念和高级用法。"
        },
        {
            "id": 2,
            "title": f"{keyword} 入门教程",
            "link": f"https://example.com/{keyword}-tutorial",
            "abstract": f"学习 {keyword} 的基础知识，适合初学者。"
        },
        {
            "id": 3,
            "title": f"{keyword} 最佳实践",
            "link": f"https://example.com/{keyword}-best-practices", 
            "abstract": f"了解在使用 {keyword} 时的最佳实践和常见陷阱。"
        }
    ]

# HTML模板
HTML_TEMPLATE = '''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>智能搜索系统</title>
    <style>
        * { 
            margin: 0; 
            padding: 0; 
            box-sizing: border-box; 
        }
        
        body { 
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }
        
        .container { 
            max-width: 1200px; 
            margin: 0 auto; 
            background: white; 
            border-radius: 15px; 
            box-shadow: 0 20px 40px rgba(0,0,0,0.1); 
            overflow: hidden;
        }
        
        .header { 
            background: linear-gradient(135deg, #2c3e50 0%, #3498db 100%);
            color: white; 
            padding: 30px; 
            text-align: center; 
            position: relative;
        }
        
        .header h1 {
            font-size: 2.5em;
            margin-bottom: 10px;
            font-weight: 300;
        }
        
        .header p {
            font-size: 1.2em;
            opacity: 0.9;
        }
        
        .status-indicator { 
            position: absolute; 
            top: 20px; 
            right: 20px; 
            padding: 8px 16px; 
            border-radius: 20px; 
            font-size: 14px;
            font-weight: bold;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .status-online { 
            background: #27ae60; 
            color: white; 
        }
        
        .status-offline { 
            background: #e74c3c; 
            color: white; 
        }
        
        .status-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            animation: pulse 2s infinite;
        }
        
        .status-online .status-dot {
            background: #2ecc71;
        }
        
        .status-offline .status-dot {
            background: #e74c3c;
        }
        
        @keyframes pulse {
            0% { opacity: 1; }
            50% { opacity: 0.5; }
            100% { opacity: 1; }
        }
        
        .search-section { 
            padding: 40px; 
            background: #f8f9fa;
        }
        
        .search-box { 
            display: flex; 
            margin-bottom: 10px; 
            position: relative; 
            max-width: 800px;
            margin: 0 auto 20px;
        }
        
        .search-input { 
            flex: 1; 
            padding: 18px 20px; 
            border: 3px solid #e0e0e0; 
            border-radius: 50px 0 0 50px; 
            font-size: 18px; 
            outline: none;
            transition: all 0.3s ease;
        }
        
        .search-input:focus { 
            border-color: #3498db; 
            box-shadow: 0 0 20px rgba(52, 152, 219, 0.3);
        }
        
        .search-button { 
            padding: 18px 35px; 
            background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
            color: white; 
            border: none; 
            border-radius: 0 50px 50px 0; 
            cursor: pointer; 
            font-size: 18px; 
            font-weight: bold;
            transition: all 0.3s ease;
        }
        
        .search-button:hover { 
            background: linear-gradient(135deg, #2980b9 0%, #3498db 100%);
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(52, 152, 219, 0.4);
        }
        
        .search-button:active {
            transform: translateY(0);
        }
        
        .search-button:disabled {
            background: #bdc3c7;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }
        
        .suggestions { 
            position: absolute; 
            top: 100%; 
            left: 10px; 
            right: 10px; 
            background: white; 
            border: 2px solid #3498db;
            border-top: none; 
            border-radius: 0 0 15px 15px; 
            box-shadow: 0 10px 25px rgba(0,0,0,0.1);
            z-index: 1000; 
            display: none;
            max-height: 300px;
            overflow-y: auto;
        }
        
        .suggestion-item { 
            padding: 15px 20px; 
            cursor: pointer; 
            border-bottom: 1px solid #ecf0f1; 
            transition: background-color 0.2s;
            font-size: 16px;
        }
        
        .suggestion-item:hover { 
            background-color: #f8f9fa; 
            color: #3498db;
        }
        
        .suggestion-item:last-child { 
            border-bottom: none; 
        }
        
        .results-section { 
            padding: 0 40px 40px; 
        }
        
        .results-header { 
            font-size: 1.5em; 
            margin-bottom: 20px; 
            color: #2c3e50; 
            border-bottom: 2px solid #ecf0f1;
            padding-bottom: 10px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .results-count { 
            color: #7f8c8d; 
            font-size: 0.9em; 
        }
        
        .results { 
            display: grid; 
            gap: 20px;
        }
        
        .result-item { 
            background: #f8f9fa; 
            border-radius: 10px; 
            padding: 25px; 
            border-left: 5px solid #3498db;
            transition: all 0.3s ease;
            box-shadow: 0 5px 15px rgba(0,0,0,0.05);
        }
        
        .result-item:hover { 
            transform: translateY(-5px); 
            box-shadow: 0 10px 25px rgba(0,0,0,0.1);
            border-left-color: #e74c3c;
        }
        
        .result-title { 
            font-size: 1.4em; 
            font-weight: bold; 
            margin-bottom: 12px; 
            color: #2c3e50;
        }
        
        .result-title a {
            color: inherit;
            text-decoration: none;
            transition: color 0.2s;
        }
        
        .result-title a:hover {
            color: #3498db;
        }
        
        .result-link { 
            color: #27ae60; 
            font-size: 0.95em; 
            margin-bottom: 15px; 
            display: block; 
            word-break: break-all;
        }
        
        .result-abstract { 
            color: #5d6d7e; 
            line-height: 1.6; 
            font-size: 1em;
        }
        
        .loading { 
            text-align: center; 
            padding: 40px; 
            color: #7f8c8d;
        }
        
        .loading-spinner {
            border: 5px solid #f3f3f3;
            border-top: 5px solid #3498db;
            border-radius: 50%;
            width: 50px;
            height: 50px;
            animation: spin 1s linear infinite;
            margin: 0 auto 20px;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .no-results { 
            text-align: center; 
            padding: 40px; 
            color: #7f8c8d; 
            font-size: 1.2em;
        }
        
        .error-message { 
            text-align: center; 
            padding: 20px; 
            background: #e74c3c; 
            color: white; 
            border-radius: 10px; 
            margin: 20px 0;
        }
        
        .warning-message {
            text-align: center;
            padding: 20px;
            background: #f39c12;
            color: white;
            border-radius: 10px;
            margin: 20px 0;
        }
        
        .footer {
            text-align: center;
            padding: 20px;
            background: #ecf0f1;
            color: #7f8c8d;
            margin-top: 40px;
        }
        
        @media (max-width: 768px) {
            .search-box {
                flex-direction: column;
            }
            
            .search-input {
                border-radius: 25px;
                margin-bottom: 10px;
            }
            
            .search-button {
                border-radius: 25px;
                width: 100%;
            }
            
            .header h1 {
                font-size: 2em;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🔍 智能搜索系统</h1>
            <p>基于TCP协议的分布式搜索解决方案</p>
            <div id="statusIndicator" class="status-indicator status-offline">
                <div class="status-dot"></div>
                <span>TCP服务器离线</span>
            </div>
        </div>
        
        <div class="search-section">
            <div class="search-box">
                <input type="text" class="search-input" id="searchInput" 
                       placeholder="输入搜索关键词..." autocomplete="off">
                <button class="search-button" id="searchButton">
                    <span id="buttonText">搜索</span>
                    <div id="buttonSpinner" style="display:none;">搜索中...</div>
                </button>
                <div class="suggestions" id="suggestions"></div>
            </div>
        </div>
        
        <div class="results-section">
            <div class="results-header">
                搜索结果 <span class="results-count" id="resultsCount"></span>
            </div>
            <div class="results" id="results">
                <div class="info-message">
                    <p>请输入关键词开始搜索，系统将为您提供最相关的搜索结果</p>
                </div>
            </div>
        </div>
        
        <div class="footer">
            <p>© 2024 智能搜索系统 | Linux TCP服务器 + HTTP网关架构</p>
        </div>
    </div>

    <script>
        // 获取DOM元素
        const searchInput = document.getElementById('searchInput');
        const searchButton = document.getElementById('searchButton');
        const buttonText = document.getElementById('buttonText');
        const buttonSpinner = document.getElementById('buttonSpinner');
        const suggestions = document.getElementById('suggestions');
        const results = document.getElementById('results');
        const resultsCount = document.getElementById('resultsCount');
        const statusIndicator = document.getElementById('statusIndicator');
        
        // 延迟搜索建议请求
        let suggestionTimeout;
        let currentSearchTerm = '';
        
        // 检查服务器状态
        function checkServerStatus() {
            fetch('/health')
                .then(response => {
                    if (!response.ok) {
                        throw new Error('健康检查失败');
                    }
                    return response.json();
                })
                .then(data => {
                    if (data.tcp_connected) {
                        statusIndicator.className = 'status-indicator status-online';
                        statusIndicator.innerHTML = '<div class="status-dot"></div><span>TCP服务器在线</span>';
                    } else {
                        statusIndicator.className = 'status-indicator status-offline';
                        statusIndicator.innerHTML = '<div class="status-dot"></div><span>TCP服务器离线（使用模拟数据）</span>';
                    }
                })
                .catch(error => {
                    console.error('状态检查失败:', error);
                    statusIndicator.className = 'status-indicator status-offline';
                    statusIndicator.innerHTML = '<div class="status-dot"></div><span>状态检查失败</span>';
                });
        }
        
        // 页面加载完成后检查状态
        window.addEventListener('load', function() {
            checkServerStatus();
            searchInput.focus();
            
            // 每30秒检查一次服务器状态
            setInterval(checkServerStatus, 30000);
        });
        
        // 输入框输入事件
        searchInput.addEventListener('input', function() {
            clearTimeout(suggestionTimeout);
            const keyword = this.value.trim();
            currentSearchTerm = keyword;
            
            if (keyword) {
                suggestionTimeout = setTimeout(() => {
                    fetchSuggestions(keyword);
                }, 300);
            } else {
                hideSuggestions();
                showInitialState();
            }
        });
        
        // 输入框焦点事件
        searchInput.addEventListener('focus', function() {
            if (this.value.trim()) {
                fetchSuggestions(this.value);
            }
        });
        
        // 输入框失去焦点事件
        searchInput.addEventListener('blur', function() {
            // 延迟隐藏建议列表，以便点击建议项
            setTimeout(hideSuggestions, 200);
        });
        
        // 搜索按钮点击事件
        searchButton.addEventListener('click', performSearch);
        
        // 输入框回车事件
        searchInput.addEventListener('keypress', function(e) {
            if (e.key === 'Enter') {
                performSearch();
            }
        });
        
        // 获取搜索建议
        function fetchSuggestions(keyword) {
            console.log('🔍 获取搜索建议:', keyword);
            
            fetch('/suggest', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ keyword: keyword })
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error('网络响应不正常');
                }
                return response.json();
            })
            .then(data => {
                console.log('✅ 收到建议响应:', data);
                displaySuggestions(data.suggestions, keyword);
            })
            .catch(error => {
                console.error('获取搜索建议失败:', error);
                hideSuggestions();
            });
        }
        
        // 显示搜索建议
        function displaySuggestions(suggestionList, keyword) {
            if (!suggestionList || suggestionList.length === 0) {
                hideSuggestions();
                return;
            }
            
            suggestions.innerHTML = '';
            
            suggestionList.forEach(suggestion => {
                const item = document.createElement('div');
                item.className = 'suggestion-item';
                
                // 高亮匹配的关键字
                let displayText = suggestion;
                if (keyword) {
                    const regex = new RegExp(`(${keyword})`, 'gi');
                    displayText = suggestion.replace(regex, '<span style="color: #e74c3c; font-weight: bold;">$1</span>');
                }
                
                item.innerHTML = displayText;
                
                item.addEventListener('mousedown', function(e) {
                    e.preventDefault(); // 防止输入框失去焦点
                    searchInput.value = suggestion;
                    hideSuggestions();
                    performSearch();
                });
                
                suggestions.appendChild(item);
            });
            
            suggestions.style.display = 'block';
        }
        
        // 隐藏搜索建议
        function hideSuggestions() {
            suggestions.style.display = 'none';
        }
        
        // 执行搜索
        function performSearch() {
            const keyword = searchInput.value.trim();
            if (!keyword) {
                showMessage('请输入搜索关键词', 'warning');
                return;
            }
            
            hideSuggestions();
            showLoading();
            setButtonLoading(true);
            
            console.log('🔍 执行搜索:', keyword);
            
            fetch('/search', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ keyword: keyword })
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error('搜索请求失败');
                }
                return response.json();
            })
            .then(data => {
                console.log('✅ 收到搜索结果:', data);
                displayResults(data.results, keyword);
                setButtonLoading(false);
            })
            .catch(error => {
                console.error('搜索失败:', error);
                displayError('搜索失败，请检查网络连接或稍后重试');
                setButtonLoading(false);
            });
        }
        
        // 设置按钮加载状态
        function setButtonLoading(loading) {
            if (loading) {
                buttonText.style.display = 'none';
                buttonSpinner.style.display = 'block';
                searchButton.disabled = true;
            } else {
                buttonText.style.display = 'block';
                buttonSpinner.style.display = 'none';
                searchButton.disabled = false;
            }
        }
        
        // 显示加载状态
        function showLoading() {
            results.innerHTML = `
                <div class="loading">
                    <div class="loading-spinner"></div>
                    <p>正在搜索中，请稍候...</p>
                </div>
            `;
            resultsCount.textContent = '搜索中...';
        }
        
        // 显示初始状态
        function showInitialState() {
            results.innerHTML = `
                <div class="info-message">
                    <p>请输入关键词开始搜索，系统将为您提供最相关的搜索结果</p>
                </div>
            `;
            resultsCount.textContent = '';
        }
        
        // 显示搜索结果
        function displayResults(resultsData, keyword) {
            if (!resultsData || resultsData.length === 0) {
                results.innerHTML = `
                    <div class="no-results">
                        <p>没有找到与 "<strong>${escapeHtml(keyword)}</strong>" 相关的结果</p>
                        <p>请尝试使用其他关键词或检查拼写</p>
                    </div>
                `;
                resultsCount.textContent = '(0 个结果)';
                return;
            }
            
            let html = '';
            resultsData.forEach(result => {
                html += `
                    <div class="result-item">
                        <div class="result-title">
                            <a href="${result.link || '#'}" target="_blank">${escapeHtml(result.title || '无标题')}</a>
                        </div>
                        <a href="${result.link || '#'}" class="result-link" target="_blank">${result.link || '无链接'}</a>
                        <div class="result-abstract">${escapeHtml(result.abstract || '无摘要')}</div>
                    </div>
                `;
            });
            
            results.innerHTML = html;
            resultsCount.textContent = `(${resultsData.length} 个结果)`;
        }
        
        // 显示错误信息
        function displayError(message) {
            results.innerHTML = `
                <div class="error-message">
                    <p>${message}</p>
                </div>
            `;
            resultsCount.textContent = '';
        }
        
        // 显示警告信息
        function displayWarning(message) {
            results.innerHTML = `
                <div class="warning-message">
                    <p>${message}</p>
                </div>
            `;
            resultsCount.textContent = '';
        }
        
        // 显示普通消息
        function showMessage(message, type = 'info') {
            const messageClass = type === 'error' ? 'error-message' : 
                               type === 'warning' ? 'warning-message' : 'loading';
            
            results.innerHTML = `
                <div class="${messageClass}">
                    <p>${message}</p>
                </div>
            `;
            resultsCount.textContent = '';
        }
        
        // HTML转义函数
        function escapeHtml(unsafe) {
            if (!unsafe) return '';
            return unsafe
                .replace(/&/g, "&amp;")
                .replace(/</g, "&lt;")
                .replace(/>/g, "&gt;")
                .replace(/"/g, "&quot;")
                .replace(/'/g, "&#039;");
        }
        
        // 添加调试函数到全局作用域
        window.debugSearch = function() {
            console.log('=== 搜索系统调试信息 ===');
            console.log('搜索输入值:', searchInput.value);
            console.log('建议框显示状态:', suggestions.style.display);
            console.log('建议框内容:', suggestions.innerHTML);
            console.log('结果框内容:', results.innerHTML);
            
            // 手动触发一次建议请求
            if (searchInput.value.trim()) {
                console.log('手动触发建议请求...');
                fetchSuggestions(searchInput.value.trim());
            }
        };
    </script>
</body>
</html>
'''

@app.route('/')
def index():
    """提供搜索页面"""
    return render_template_string(HTML_TEMPLATE)

@app.route('/suggest', methods=['POST'])
def get_suggestions():
    """获取搜索建议"""
    data = request.get_json()
    keyword = data.get('keyword', '')
    
    if not keyword:
        return jsonify({'suggestions': []})
    
    print(f"🔍 获取搜索建议: '{keyword}'")
    
    # 获取TCP客户端
    client = get_tcp_client()
    if not client:
        # TCP服务器不可用，返回模拟数据
        print("⚠️ TCP服务器不可用，返回模拟建议")
        suggestions = create_mock_suggestions(keyword)
        return jsonify({'suggestions': suggestions})
    
    # 发送关键字建议请求到TCP服务器 (tag=1)
    start_time = time.time()
    response = client.send_message(1, keyword)
    elapsed_time = time.time() - start_time
    
    if response and response['tag'] == 1:
        try:
            suggestions = json.loads(response['value'])
            print(f"✅ 收到建议响应: {len(suggestions)} 条建议, 耗时: {elapsed_time:.2f}s")
            return jsonify({'suggestions': suggestions})
        except Exception as e:
            print(f"❌ 解析建议数据失败: {e}")
            # 返回模拟数据作为备选
            suggestions = create_mock_suggestions(keyword)
            return jsonify({'suggestions': suggestions})
    
    # 如果TCP服务器无响应，返回模拟数据
    print(f"⚠️ TCP服务器无响应，返回模拟建议，耗时: {elapsed_time:.2f}s")
    suggestions = create_mock_suggestions(keyword)
    return jsonify({'suggestions': suggestions})

@app.route('/search', methods=['POST'])
def search():
    """执行搜索"""
    data = request.get_json()
    keyword = data.get('keyword', '')
    
    if not keyword:
        return jsonify({'results': []})
    
    print(f"🔍 执行搜索: '{keyword}'")
    
    # 获取TCP客户端
    client = get_tcp_client()
    if not client:
        # TCP服务器不可用，返回模拟数据
        print("⚠️ TCP服务器不可用，返回模拟结果")
        results = create_mock_results(keyword)
        return jsonify({'results': results})
    
    # 发送搜索请求到TCP服务器 (tag=2)
    start_time = time.time()
    response = client.send_message(2, keyword)
    elapsed_time = time.time() - start_time
    
    if response and response['tag'] == 2:
        try:
            results = json.loads(response['value'])
            # 确保结果是列表格式
            if isinstance(results, dict):
                results = [results]
            print(f"✅ 收到搜索结果: {len(results)} 条结果, 耗时: {elapsed_time:.2f}s")
            return jsonify({'results': results})
        except Exception as e:
            print(f"❌ 解析搜索结果失败: {e}")
            # 返回模拟数据作为备选
            results = create_mock_results(keyword)
            return jsonify({'results': results})
    
    # 如果TCP服务器无响应，返回模拟数据
    print(f"⚠️ TCP服务器无响应，返回模拟结果，耗时: {elapsed_time:.2f}s")
    results = create_mock_results(keyword)
    return jsonify({'results': results})

@app.route('/health')
def health_check():
    """健康检查端点"""
    client = get_tcp_client()
    if client and client.connected:
        return jsonify({
            'status': 'healthy', 
            'tcp_connected': True,
            'message': 'TCP服务器连接正常'
        })
    else:
        return jsonify({
            'status': 'unhealthy', 
            'tcp_connected': False,
            'message': 'TCP服务器连接失败，使用模拟数据'
        }), 503

if __name__ == '__main__':
    # 在启动时测试TCP连接
    print("🚀 正在初始化TCP客户端...")
    client = get_tcp_client()
    if client:
        print("✅ TCP客户端初始化成功")
    else:
        print("⚠️ TCP客户端初始化失败 - 将使用模拟数据")
    
    # 启动Flask应用
    print("🌐 启动HTTP网关服务器...")
    print("📍 访问 http://192.168.7.185:5000 使用搜索功能")
    print("📍 或者访问 http://127.0.0.1:5000 (本地)")
    try:
        app.run(host='0.0.0.0', port=5000, debug=True)
    except KeyboardInterrupt:
        print("\n👋 服务器已关闭")
        if client:
            client.close() 
